<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
<head>
<title>Layout management in PyQt4</title>
<link rel="stylesheet" href="/cfg/format.css" type="text/css">
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="keywords" content="PyQt, PyQt4, layout management, tutorial, Python, Linux">
<meta name="description" content="In this part of the PyQt4 tutorial, we work 
with layout management.">
<meta name="language" content="en">
<meta name="author" content="Jan Bodnar">
<meta name="distribution" content="global">

<script type="text/javascript" src="/lib/jquery.js"></script>
<script type="text/javascript" src="/lib/common.js"></script>

</head>

<body>

<div class="container">

<div id="wide_ad" class="ltow">
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* 160x600, August 2011 */
google_ad_slot = "2484182563";
google_ad_width = 160;
google_ad_height = 600;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>


<div class="content">

<a href="/" title="Home">Home</a>&nbsp;
<a href=".." title="Home">Contents</a>


<h1>Layout management in PyQt4</h1>


<p>
Important thing in programming is the layout management. Layout management 
is the way how we place the widgets on the window. The management can be 
done in two ways. We can use <b>absolute positioning</b> or <b>layout classes</b>.
</p>

<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* NewSquare */
google_ad_slot = "0364418177";
google_ad_width = 300;
google_ad_height = 250;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 

<h2>Absolute positioning</h2>

<p>
The programmer specifies the position and the size of each widget in pixels. 
When you use absolute positioning, you have to understand several things. 
</p>

<ul>
  <li>the size and the position of a widget do not change, if you resize a window</li>
  <li>applications might look different on various platforms</li>
  <li>changing fonts in your application might spoil the layout</li>
  <li>
  if you decide to change your layout, you must completely redo 
  your layout, which is tedious and time consuming
  </li>
</ul>

<pre class="code">
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PyQt4 tutorial 

This example shows three labels on a window
using absolute positioning. 

author: Jan Bodnar
website: zetcode.com 
last edited: October 2011
"""

import sys
from PyQt4 import QtGui

class Example(QtGui.QWidget):
    
    def __init__(self):
        super(Example, self).__init__()
        
        self.initUI()
        
    def initUI(self):
        
        lbl1 = QtGui.QLabel('Zetcode', self)
        lbl1.move(15, 10)

        lbl2 = QtGui.QLabel('tutorials', self)
        lbl2.move(35, 40)
        
        lbl3 = QtGui.QLabel('for programmers', self)
        lbl3.move(55, 70)        
        
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Absolute')    
        self.show()
        
def main():
    
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

</pre>

<p>
We simply call the <code>move()</code> method to position our widgets. In our case 
these are labels. We position them by providing the x and the y coordinates. The 
beginning of the coordinate system is at the left top corner. The x values 
grow from left to right. The y values grow from top to bottom.
</p>

<br>
<img src="/img/gui/pyqt4/absolute.png" alt="Absolute positioning">
<div class="figure">Figure: Absolute positioning</div>


<h2>Box Layout</h2>


<p>
Layout management with layout classes is much more flexible and practical. 
It is the preferred way to place widgets on a window. The basic layout 
classes are <code>QtGui.QHBoxLayout</code> and <code>QtGui.QVBoxLayout</code>. They line up 
widgets horizontally and vertically. 
</p>

<p>
Imagine that we wanted to place two buttons in the right bottom corner. To create 
such a layout, we will use one horizontal and one vertical box. To create 
the neccessary space, we will add a <b>stretch factor</b>.
</p>

<pre class="code">
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PyQt4 tutorial 

In this example, we position two push
buttons in the bottom-right corner 
of the window. 

author: Jan Bodnar
website: zetcode.com 
last edited: October 2011
"""

import sys
from PyQt4 import QtGui

class Example(QtGui.QWidget):
    
    def __init__(self):
        super(Example, self).__init__()
        
        self.initUI()
        
    def initUI(self):
        
        okButton = QtGui.QPushButton("OK")
        cancelButton = QtGui.QPushButton("Cancel")

        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(okButton)
        hbox.addWidget(cancelButton)

        vbox = QtGui.QVBoxLayout()
        vbox.addStretch(1)
        vbox.addLayout(hbox)
        
        self.setLayout(vbox)    
        
        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Buttons')    
        self.show()
        
def main():
    
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
</pre>

<p>
The example places two buttons in the bottom-right corner of the window. 
They stay there when we resize the application window. We use both
<code>QtGui.HBoxLayout</code> and <code>QtGui.QVBoxLayout</code>. 
</p>

<pre class="explanation">
okButton = QtGui.QPushButton("OK")
cancelButton = QtGui.QPushButton("Cancel")
</pre>

<p>
Here we create two push buttons.
</p>

<pre class="explanation">
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(okButton)
hbox.addWidget(cancelButton)
</pre>

<p>
We create a horizontal box layout. Add a stretch factor and both buttons. 
The stretch adds a stretchable space before the two buttons. 
This will push them to the right of the window.
</p>

<pre class="explanation">
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
</pre>

<p>
To create the necessary layout, we put a horizontal layout into a vertical one. 
The stretch factor in the vertical box will push the horizontal box 
with the buttons to the bottom of the window. 
</p>

<pre class="explanation">
self.setLayout(vbox)
</pre>

<p>
Finally, we set the main layout of the window. 
</p>

<br>
<img src="/img/gui/pyqt4/buttons.png" alt="Buttons">
<div class="figure">Figure: Buttons</div>


<h2>QtGui.QGridLayout</h2>

<p>
The most universal layout class is the grid layout. This layout 
divides the space into rows and columns.
To create a grid layout, we use the <code>QtGui.QGridLayout</code> class. 
</p>

<pre class="code">
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PyQt4 tutorial 

In this example, we create a skeleton
of a calculator using a QtGui.QGridLayout.

author: Jan Bodnar
website: zetcode.com 
last edited: October 2011
"""

import sys
from PyQt4 import QtGui


class Example(QtGui.QWidget):
    
    def __init__(self):
        super(Example, self).__init__()
        
        self.initUI()
        
    def initUI(self):
        
        names = ['Cls', 'Bck', '', 'Close', '7', '8', '9', '/',
                '4', '5', '6', '*', '1', '2', '3', '-',
                '0', '.', '=', '+']

        grid = QtGui.QGridLayout()

        j = 0
        pos = [(0, 0), (0, 1), (0, 2), (0, 3),
                (1, 0), (1, 1), (1, 2), (1, 3),
                (2, 0), (2, 1), (2, 2), (2, 3),
                (3, 0), (3, 1), (3, 2), (3, 3 ),
                (4, 0), (4, 1), (4, 2), (4, 3)]

        for i in names:
            button = QtGui.QPushButton(i)
            if j == 2:
                grid.addWidget(QtGui.QLabel(''), 0, 2)
            else: grid.addWidget(button, pos[j][0], pos[j][1])
            j = j + 1

        self.setLayout(grid)   
        
        self.move(300, 150)
        self.setWindowTitle('Calculator')    
        self.show()
        
def main():
    
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
</pre>


<p>
In our example, we create a grid of buttons. To fill one gap, 
we add one <code>QtGui.QLabel</code> widget. 
</p>

<pre class="explanation">
grid = QtGui.QGridLayout()
</pre>

<p>
Here we create a grid layout. 
</p>

<pre class="explanation">
if j == 2:
    grid.addWidget(QtGui.QLabel(''), 0, 2)
else: grid.addWidget(button, pos[j][0], pos[j][1])
</pre>

<p>
To add a widget to a grid, we call the <code>addWidget()</code> method. 
The arguments are the widget, the row and the column number.
</p>

<br>
<img src="/img/gui/pyqt4/calculator.png" alt="Calculator skeleton">
<div class="figure">Figure: Calculator skeleton</div>


<h2>Review example</h2>

<p>
Widgets can span multiple columns or rows in a grid. In the next 
example we illustrate this. 
</p>

<pre class="code">
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PyQt4 tutorial 

In this example, we create a bit
more complicated window layout using
the QtGui.QGridLayout manager. 

author: Jan Bodnar
website: zetcode.com 
last edited: October 2011
"""

import sys
from PyQt4 import QtGui


class Example(QtGui.QWidget):
    
    def __init__(self):
        super(Example, self).__init__()
        
        self.initUI()
        
    def initUI(self):
        
        title = QtGui.QLabel('Title')
        author = QtGui.QLabel('Author')
        review = QtGui.QLabel('Review')

        titleEdit = QtGui.QLineEdit()
        authorEdit = QtGui.QLineEdit()
        reviewEdit = QtGui.QTextEdit()

        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(title, 1, 0)
        grid.addWidget(titleEdit, 1, 1)

        grid.addWidget(author, 2, 0)
        grid.addWidget(authorEdit, 2, 1)

        grid.addWidget(review, 3, 0)
        grid.addWidget(reviewEdit, 3, 1, 5, 1)
        
        self.setLayout(grid) 
        
        self.setGeometry(300, 300, 350, 300)
        self.setWindowTitle('Review')    
        self.show()
        
def main():
    
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()
</pre>

<p>
We create a window in which we have three labels, two line edits and
one text edit widget. The layout is done with the <code>QtGui.QGridLayout</code>.
</p>

<pre class="explanation">
grid = QtGui.QGridLayout()
grid.setSpacing(10)
</pre>

<p>
We create a grid layout and set spacing between widgets. 
</p>

<pre class="explanation">
grid.addWidget(reviewEdit, 3, 1, 5, 1)
</pre>

<p>
If we add a widget to a grid, we can provide row span and column 
span of the widget. In our case, we make the reviewEdit widget span 5 rows.
</p>


<br>
<img src="/img/gui/pyqt4/review.png" alt="Review example">
<div class="figure">Figure: Review example</div>

<hr class="btm">

<p>
This part of the PyQt4 tutorial was dedicated to layout management.
</p>

<br>
<div class="center"> 
<script type="text/javascript"><!--
google_ad_client = "pub-9706709751191532";
/* horizontal */
google_ad_slot = "1734478269";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script> 
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> 
</script> 
</div>
<br>


<div class="botNav, center">
<span class="botNavItem"><a href="/">Home</a></span> ‡ <span class="botNavItem"><a href="..">Contents</a></span> ‡ 
<span class="botNavItem"><a href="#">Top of Page</a></span>
</div>


<div class="footer">
<div class="signature">
<a href="/">ZetCode</a> last modified October 8, 2011  <span class="copyright">&copy; 2007 - 2013 Jan Bodnar</span>
</div>
</div>

</div> <!-- content -->

</div> <!-- container -->


</body>
</html>

